package main

import (
	"bufio"
	"crypto/rand"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

var (
	baseDirName,folderPath string
	errfp *os.File
	lock *sync.RWMutex = new(sync.RWMutex)
	wg sync.WaitGroup
	cchan chan struct{}
)

func WriteLog(str []byte) {
	lock.Lock()
	log.Print(string(str))
	_, _ = errfp.Write(str)
	lock.Unlock()
}
func run(videourl string) {
	response, err := http.Get(videourl)
	if err != nil {
		WriteLog([]byte(strings.Join([]string{time.Now().Format("2006-01-02 15:04:05"), videourl, "请求失败",err.Error()}, "->") + "\n"))
	}else {
		CreateDateDir()
		response.Close = true
		defer response.Body.Close()
		body, _ := ioutil.ReadAll(response.Body)
		fp, err  := os.OpenFile(folderPath+"/index.m3u8", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
		if err != nil {
			fmt.Println("打开文件失败:"+err.Error())
			return
		}
		defer fp.Close()
		fp.Write(body)
		countSplit := strings.Split(videourl, "/")
		uri := strings.Join(countSplit[:len(countSplit)-1], "/")
		scanner := bufio.NewScanner(strings.NewReader(string(body)))
		//var readCount = 0
		for scanner.Scan() {
			lineText := scanner.Text()
			if lineText[len(lineText)-2:] == "ts" {
				wg.Add(1)
				cchan <- struct{}{}
				go dowts(uri + "/" + lineText,lineText)
			}
		}
		wg.Wait()
		//ffmpeg -allowed_extensions ALL -protocol_whitelist "file,http,crypto,tcp" -i index.m3u8 -c copy aaa.mp4
		//WriteLog([]byte(strings.Join([]string{time.Now().Format("2006-01-02 15:04:05"), uri, response.Status}, "->") + "\n"))
	}
}

func dowts(s string,filename string) {
	fmt.Println("<<下载开始Filename:"+filename)
	response, err := http.Get(s)
	if err != nil {
		wg.Done()
		<- cchan // 执行完毕，释放资源
		WriteLog([]byte(strings.Join([]string{time.Now().Format("2006-01-02 15:04:05"), s, "请求失败",err.Error()}, "->") + "\n"))
	}else {
		response.Close = true
		defer response.Body.Close()
		tsBody ,_ := ioutil.ReadAll(response.Body)
		fp, err  := os.OpenFile(folderPath+"/"+filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
		if err != nil {
			fmt.Println("打开文件失败:"+err.Error())
			return
		}
		defer fp.Close()
		fp.Write(tsBody)
		fmt.Println(">>下载结束Filename:"+filename)
		<- cchan // 执行完毕，释放资源
		wg.Done()
	}
}
//basePath是固定目录路径
func CreateDateDir() {
	randInt,_ := rand.Int(rand.Reader, big.NewInt(100))
	folderName := time.Now().Format("2006-01-02")+"-"+randInt.String()
	folderPath = filepath.Join(baseDirName, folderName)
	if _, err := os.Stat(folderPath); os.IsNotExist(err) {
		// 必须分成两步
		// 先创建文件夹
		os.Mkdir(folderPath, 0777)
		// 再修改权限
		os.Chmod(folderPath, 0777)
	}
	//return folderPath, folderName
}
//var redisAddress = redisconfig{Address: "127.0.0.1:6379"}
//var redisAuth = redisconfig{Auth: "" }
func main() {
	//fmt.Print(os.Args[1])
	start := time.Now() // 获取当前时间
	count := 100
	cchan = make(chan struct{}, count) // 控制任务并发的chan
	var uri  *string = flag.String("uri", "", "m3u8地址")
	var mname  *string = flag.String("mname", "index.mp4", "保存的mp4名称")
	flag.Parse()
	dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))//获取执行程序当前目录
	baseDirName = dir
	errfp, _   = os.OpenFile(folderPath+"/error.log", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
	defer errfp.Close()
	run(*uri)
	m3u8ToMp4Cmd := []string{"-allowed_extensions","ALL","-i", folderPath+"/index.m3u8", "-c","copy", *mname+".mp4"}
	cmd := exec.Command("ffmpeg",m3u8ToMp4Cmd...)
	cmd.Run()
	os.RemoveAll(folderPath)
	fmt.Println(">>程序运行总耗时:"+time.Since(start).String())

}



